package com.liu.jvm.classload;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * 运维终端类加载器
 * 我们通过了getClassDePass()方法读取了网络传输过来存储到本地的class文件的字节流数据，并对读取到的数据做了对应的解密处理（模拟），
 * 然后通过重写了父类的ClassLoader.findClass()方法，利用defineClass()方法在JVM内存中生成了最终的Class对象。
 */
public class OpsClassLoader extends ClassLoader {

    // 接收到的class文件本地的存储位置
    private String rootDirPath;

    // 构造器
    public OpsClassLoader(String rootDirPath) {
        this.rootDirPath = rootDirPath;
    }

    // 读取Class字节流并解密的方法
    private byte[] getClassDePass(String className) throws IOException {
        String classpath = rootDirPath + className;

        // 模拟文件读取过程.....
        FileInputStream fis = new FileInputStream(classpath);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int bufferSize = 1024;
        int n = 0;
        byte[] buffer = new byte[bufferSize];
        while ((n = fis.read(buffer)) != -1)
            // 模拟数据解密过程.....
            baos.write(buffer, 0, n);
        byte[] data = baos.toByteArray();

        // 模拟保存解密后的数据....
        return data;
    }

    // 重写了父类的findClass方法
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        // 读取指定的class文件
        byte[] classData = new byte[0];
        try {
            classData = getClassDePass(name);
        } catch (IOException e) {
            e.printStackTrace();
            throw new ClassNotFoundException();
        }
        // 如果没读取到数据，抛出类不存在的异常
        if (classData == null)
            throw new ClassNotFoundException();
        // 通过调用defineClass方法生成Class对象
        return defineClass(name,classData,0,classData.length);
    }
}
